/*
 * Copyright 2012 Fabian Wenzelmann
 * 
 * This file is part of Recognition-Procedures-for-Boolean-Functions.
 * 
 * Recognition-Procedures-for-Boolean-Functions is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Recognition-Procedures-for-Boolean-Functions is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Recognition-Procedures-for-Boolean-Functions.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.wenzelmf.booleanFunction.booleanExpression;

import java.util.Collection;
import java.util.Iterator;

/**
 * This class can be used to define a Boolean function given a Boolean expression.
 * <br>
 * Given an input point it simply creates an assignment for the variables that assigns 1
 * to all variables for which the related input value of the Boolean function is 1.
 * <br>
 * You can control the order in which the variables are associated with an input point,
 * see {@link #ExpressionToFunction(BooleanExpression, Collection)}.
 * 
 * @author Fabian Wenzelmann
 * @version 1.0
 *
 */
public class ExpressionToFunction extends BooleanFunction
{
	/*
	 * The Boolean expression that defines this function.
	 */
	private BooleanExpression phi;
	
	/*
	 * A collection that contains the variables in the Boolean expression, in the order
	 * the variables are associated with the input points.
	 */
	private Collection<String> variables;
	
	/**
	 * Creates a new Boolean function given an Boolean expression.
	 * <br>
	 * &phi; is the Boolean function that is used to define this Boolean function.
	 * <br>
	 * For a n-dimensional Boolean function that input is a point (a<sub>1</sub>, &hellip;, a<sub>n</sub>).
	 * To control which variable is associated with which value a<sub>i</sub> the
	 * <code>variables</code> Collection is used. So the first component a<sub>1</sub> is associated
	 * with the first variable identifier returned by the Iterator of the specified collection
	 * and so forth.
	 * <br>
	 * Ensure that the input point for this function is "big enough" for all variables
	 * that occur in the Boolean expression. So it is not allowed that the input point
	 * is of a smaller dimension than the amount of variables in the expression.
	 * <br>
	 * Note that changes to the specified Collection are reflected to the Collection
	 * in this Boolean function, so we don't create a copy of it but use it directly!
	 * 
	 * @param phi The Boolean expression that defines this Boolean function.
	 * @param variables The Collection that is used to specify the association between
	 * an input point and the variables.
	 */
	public ExpressionToFunction(BooleanExpression phi, Collection<String> variables)
	{
		this.phi = phi;
		this.variables = variables;
	}
	
	/**
	 * Creates a new Boolean function given an Boolean expression.
	 * <br>
	 * The order the input point is associated with the variables of the expression
	 * is determined by the method {@link BooleanExpression#variableSet()}, because
	 * this method returns an set you don't really know about this order.
	 * 
	 * @see #ExpressionToFunction(BooleanExpression, Collection)
	 * 
	 * @param phi The Boolean expression that defines this Boolean function.
	 */
	public ExpressionToFunction(BooleanExpression phi)
	{
		this.phi = phi;
		this.variables = phi.variableSet();
	}
	
	@Override
	public boolean getValue(Iterator<Boolean> inputPoint)
	{
		// use the input point and the variables to create an assignment
		// TODO: same problem again as I had before somewhere...
		// this will cause rehashing?
		SimpleAssignment assignment = new SimpleAssignment(variables.size());
		Iterator<String> varIt = variables.iterator();
		
		while(varIt.hasNext())
		{
			Boolean next = inputPoint.next();
			String var = varIt.next();
			if(next)
			{
				assignment.makeTrue(var);
			}
		}
		
		return Evaluator.EVALUATOR.getTruthValue(phi, assignment);
	}

	@Override
	public int getDimension()
	{
		return variables.size();
	}

	/**
	 * Returns the Collection that is used to determine the association between variables
	 * in the expression and an input point, see {@link #ExpressionToFunction(BooleanExpression, Collection)}
	 * for details.
	 * <br>
	 * Note that changes to this Collection are reflected to the Collection that is used
	 * here, so we don't create a copy or so!
	 * 
	 * @see #ExpressionToFunction(BooleanExpression, Collection)
	 * 
	 * @return The Collection that is used to determine the association between variables
	 * in the expression and an input point.
	 */
	public Collection<String> getVariables()
	{
		return variables;
	}
	
}
